﻿/*
 * Copyright (c) http://DesignBased.NET 
 * Author: http://t.163.com/Jeek
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the 
 * Software  * without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
 * A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 * 
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T163.Open.Api.WP7.Model;

namespace T163.Open.Api.WP7
{
    /// <summary>
    /// oauth service
    /// </summary>
    public class OAuthService
    {
        #region fields/properties

        internal string realm = "t163sdk4wp7";

        private OAuthRequest requestBase;

        internal RequestToken RequestToken
        {
            get;
            set;
        }

        internal string Verifier
        {
            get;
            set;
        }

        public Consumer Consumer
        {
            get;
            set;
        }

        public AccessToken AccessToken
        {
            get;
            set;
        }

        /// <summary>
        /// 当前用户
        /// </summary>
        public Users LogonUser
        {
            get;
            set;
        }

        #endregion

        /// <summary>
        /// 创建一个OAuthService实例
        /// </summary>
        public OAuthService()
        {
            if (this.Consumer != null && this.AccessToken != null && requestBase == null)
                requestBase = OAuthRequest.Create(this.Consumer, this.AccessToken).SetRealm(this.realm).SetHttpMethod(HttpMethodType.Get);
        }

        /// <summary>
        /// 创建一个OAuthService实例
        /// </summary>
        /// <param name="consumer">Consumer</param>
        /// <param name="accessToken">AccessToken</param>
        public OAuthService(Consumer consumer, AccessToken accessToken)
        {
            this.Consumer = consumer;
            this.AccessToken = accessToken;

            requestBase = OAuthRequest.Create(this.Consumer, this.AccessToken).SetRealm(this.realm).SetHttpMethod(HttpMethodType.Get);
        }

        private void HandleErrors(Exception ex, Action<Exception> fail)
        {
            WebException we = ex as WebException;

            if (we != null && we.Status == WebExceptionStatus.RequestCanceled)
                return;
            if (fail != null)
                Deployment.Current.Dispatcher.BeginInvoke(() => fail(ex));
            else
                MethedFail(ex);
        }

        private void MethedFail(Exception ex)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                MessageBox.Show(ex.Message);
            });
        }

        #region 验证
        
        /// <summary>
        /// 获取Request Token
        /// 默认 Http 方法为 GET
        /// </summary>
        /// <param name="consumer">Consumer</param>
        /// <param name="action">处理请求返回的数据</param>
        /// <returns></returns>
        public void GetRequestToken(Consumer consumer, Action<string> action)
        {
            GetRequestToken(consumer, HttpMethodType.Get, action, null);
        }

        /// <summary>
        /// 使用代理获取Request Token
        /// </summary>
        /// <param name="type">Http 方法类型</param>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void GetRequestToken(Consumer consumer, HttpMethodType type, Action<string> action, Action<Exception> fail)
        {
            this.Consumer = consumer;

            string authorizationHeader = OAuthUtility.GenerateAuthorizationHeader(
                realm,
                Urls.RequestToken,
                null,
                type,
                consumer,
                null,
                null,
                new Parameter[] { });

            HttpWebRequest req = WebRequest.Create(Urls.RequestToken) as HttpWebRequest;
            req.Headers["Authorization"] = authorizationHeader;

            try
            {
                req.BeginGetResponse(p =>
                    {
                        try
                        {
                            HttpWebRequest request = (HttpWebRequest)p.AsyncState;
                            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(p);

                            Stream responseStream = response.GetResponseStream();
                            StreamReader streamReader = new StreamReader(responseStream);

                            string responseString = streamReader.ReadToEnd();

                            List<Parameter> parameters = responseString.ParseParameters();

                            responseStream.Close();
                            streamReader.Close();
                            response.Close();

                            RequestToken requestToken = new RequestToken(
                                parameters.Single(e => e.Key == "oauth_token").Value,
                                parameters.Single(e => e.Key == "oauth_token_secret").Value
                            );

                            this.RequestToken = requestToken;

                            action(this.GetAuthorizationURL());
                        }
                        catch (Exception ex)
                        {
                            HandleErrors(ex, fail);
                        }
                    }, req);
            }
            catch (Exception ex)
            {
                HandleErrors(ex, fail);
            }
        }

        /// <summary>
        /// 使用Request Token获取用户授权地址【WEB程序使用】
        /// </summary>
        /// <param name="callback">返回的地址</param>
        /// <returns>用户授权地址</returns>
        public string GetAuthorizationURL(string callback)
        {
            return string.Format("{0}?oauth_token={1}&oauth_callback={2}", Urls.Authenticate, this.RequestToken.Token, callback);
        }

        /// <summary>
        /// 使用Request Token获取用户授权地址【桌面程序使用】
        /// </summary>
        /// <returns>用户授权地址</returns>
        public string GetAuthorizationURL()
        {
            return string.Format("{0}?oauth_token={1}&client_type=mobile", Urls.Authorize, this.RequestToken.Token);
        }

        /// <summary>
        /// 获取Access Token
        /// 默认 Http 方法为 GET
        /// </summary>
        /// <param name="verifier">PIN码</param>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void GetAccessToken(string verifier, Action<AccessToken> action, Action<Exception> fail)
        {
            GetAccessToken(verifier, HttpMethodType.Get, action, fail);
        }
        
        /// <summary>
        /// 使用代理获取Access Token
        /// </summary>
        /// <param name="accessTokenUrl">地址</param>
        /// <param name="verifier">PIN码</param>
        /// <param name="type">Http 方法类型</param>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void GetAccessToken(string verifier, HttpMethodType type, Action<AccessToken> action, Action<Exception> fail)
        {
            this.Verifier = verifier;

            string authorizationHeader = OAuthUtility.GenerateAuthorizationHeader(
                realm,
                Urls.AccessToken,
                string.Empty,
                type,
                this.Consumer,
                this.RequestToken,
                verifier,
                new Parameter[] { });

            HttpWebRequest req = WebRequest.Create(Urls.AccessToken) as HttpWebRequest;
            req.Headers["Authorization"] = authorizationHeader;

            try
            {
                req.BeginGetResponse(p =>
                {
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)p.AsyncState;
                        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(p);

                        Stream responseStream = response.GetResponseStream();
                        StreamReader streamReader = new StreamReader(responseStream);

                        string responseString = streamReader.ReadToEnd();

                        List<Parameter> parameters = responseString.ParseParameters();

                        responseStream.Close();
                        streamReader.Close();
                        response.Close();

                        AccessToken accessToken = new AccessToken(
                            parameters.Single(e => e.Key == "oauth_token").Value,
                            parameters.Single(e => e.Key == "oauth_token_secret").Value
                        );

                        this.AccessToken = accessToken;

                        requestBase = OAuthRequest.Create(this.Consumer, this.AccessToken).SetRealm(this.realm).SetHttpMethod(HttpMethodType.Get);

                        action(accessToken);
                    }
                    catch (Exception ex)
                    {
                        HandleErrors(ex, fail);
                    }
                }, req);
            }
            catch (Exception ex)
            {
                HandleErrors(ex, fail);
            }
        }

        /// <summary>
        /// 验证用户是否登录成功并返回用户信息
        /// 【获取Access Token 后必须先调用这个方法获取用户信息后才能进行其他操作】
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns>用户或NULL</returns>
        public void VerifyCredentials(Action<Users> action, Action<Exception> fail)
        {
            var verifyRequest = OAuthRequest.Create(this.Consumer, this.AccessToken).SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.VerifyCredential).CommitRequest();
            verifyRequest.GetResponse(response =>
            {
                if (response.IsSuccess && !string.IsNullOrWhiteSpace(response.ResponseText))
                {
                    LogonUser = JsonConvert.DeserializeObject<Users>(response.ResponseText);

                    action(LogonUser);
                }
            }, fail);
        }

        #endregion

        #region 微博列表

        /// <summary>
        /// 获取公共微博列表
        /// </summary>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性</param>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns>微博列表</returns>
        public void GetPublicTimeLine(Action<OAuthResponse> action, Action<Exception> fail, bool trimUser = false)
        {
            var ptlRequest = requestBase.SetUrl(Urls.PublicTimeLine).AddParameter(new Parameter("trim_user", trimUser ? "true" : "false")).CommitRequest();
            ptlRequest.GetResponse(action, fail);
        }

        /// <summary>
        /// 取得当前登录用户的微博列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="maxId">该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="trimUser">值为true时返回的user对象只包含id属性，该属性能在一定程度上减少返回的数据量</param>
        /// <param name="count">数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetHomeTimeLine(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            if (count > 200)
                throw new ArgumentException("最大数量为200条", "count");

            var request = requestBase.SetUrl(Urls.HomeTimeLine).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("trim_user", trimUser ? "true" : "false"),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取指定微博的转发列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，指定的微博id</param>
        /// <param name="count">选参数，数量，默认为30条，最大为200条</param>
        /// <param name="sinceId">可选参数，该参数需传微博id，返回此条索引之后发的微博列表，不包含此条</param>
        /// <param name="maxId">可选参数，该参数需传微博id，返回此条微博之前发的微博列表，包含此条</param>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性，该参数能在一定程度上减少返回的数据量</param>
        /// <returns></returns>
        public void GetRetweets(Action<OAuthResponse> action, Action<Exception> fail, string id, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(string.Format(Urls.Retweets, id)).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId),
                    new Parameter("trim_user", trimUser ? "true" : "false")
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取@评论当前登录用户的微博列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="maxId">该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="trimUser">值为true时返回的user对象只包含id属性，该参数能在一定程度上减少返回的数据量</param>
        /// <param name="count">数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetMentions(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            if (count > 200)
                throw new ArgumentException("最大数量为200条", "count");

            var request = requestBase.SetUrl(Urls.Mentions).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("trim_user", trimUser ? "true" : "false"),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取指定用户的微博列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="maxId">可选参数，该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="name">可选参数，用户昵称</param>
        /// <param name="screenName">可选参数，可以传user_id或screen_name</param>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性，该属性能在一定程度上减少返回的数据量</param>
        /// <param name="count">可选参数，数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetUserTimeLine(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string name = "", string screenName = "", bool trimUser = true, int count = 30, string sinceId = "", string maxId = "")
        {
            var request = requestBase.SetUrl(Urls.UserTimeLine).AddParameter(
               new Parameter[] {
                    new Parameter("name", name),
                    new Parameter("screen_name", screenName),
                    new Parameter("user_id", userId),
                    new Parameter("count", count.ToString()),
                    new Parameter("trim_user", trimUser ? "true" : "false"),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取当前登录用户所发微博被转发的列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="count">可选参数，数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetRetweetsOfMe(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, string sinceId = "")
        {
            if (count > 200)
                throw new ArgumentException("最大数量为200条", "count");

            var request = requestBase.SetUrl(Urls.RetweetsOfMe).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("since_id", sinceId)
                }).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess && result.ResponseText != null)
            //{
            //    // reference: http://stackoverflow.com/questions/612689/a-generic-list-of-anonymous-class
            //    var retweets = new { created_at = "created_at", retweeted_status = new Statues() };
            //    var retweets1 = new { created_at = "created_at1", retweeted_status = new Statues() };

            //    var rtArray = new[] { retweets, retweets1 };

            //    var lst = JsonConvert.DeserializeAnonymousType(result.ResponseText, rtArray);

            //    List<Statues> stlst = new List<Statues>();
            //    foreach (var s in lst)
            //    {
            //        stlst.Add(s.retweeted_status);
            //    }

            //    return stlst;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 获取当前登录用户发出的评论列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="maxId">可选参数，该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性，该属性能在一定程度上减少返回的数据量。默认为true</param>
        /// <param name="count">选参数，数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetCommentsByMe(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            if (count > 200)
                throw new ArgumentException("最大数量为200条", "count");

            var request = requestBase.SetUrl(Urls.CommentsByMe).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("trim_user", trimUser ? "true" : "false"),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取当前登录用户收到的评论列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="maxId">可选参数，该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性，该属性能在一定程度上减少返回的数据量。默认为true</param>
        /// <param name="count">可选参数，数量，默认为30条，最大为200条</param>
        /// <returns></returns>
        public void GetCommentsToMe(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            if (count > 200)
                throw new ArgumentException("最大数量为200条", "count");

            var request = requestBase.SetUrl(Urls.CommentsToMe).AddParameter(
                new Parameter[] {
                    new Parameter("count", count.ToString()),
                    new Parameter("trim_user", trimUser ? "true" : "false"),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 微博

        /// <summary>
        /// 发布一条微博。
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="statues">必选参数，微博内容，不得超过163个字符</param>
        /// <param name="lat">选参数，即纬度。范围在+90.0 到 -90.0，如果超出这个范围则忽略该值，必须与long参数一起使用，否则忽略该值。只有当用户的geo_enable为true时才有效</param>
        /// <param name="longGeo">可选参数,即经度。范围在+180.0到-180.0，如果超出这个范围则忽略该值，必须与lat参数一起使用，否则忽略该值。只有当用户的geo_enable为true时才有效</param>
        /// <param name="vid">可选参数,即 POI 的 ID，某一个具体的地点，比如天安门</param>
        /// <returns></returns>
        public void Update(Action<OAuthResponse> action, Action<Exception> fail, Statues statues, double lat = 0, double longGeo = 0, string vid = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.UpdateStatues).AddParameter(
                new Parameter[] { 
                    new Parameter("status", statues.Text), 
                    new Parameter("lat", lat.ToString()), 
                    new Parameter("long", longGeo.ToString()),
                    new Parameter("vid", vid)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 评论一条微博
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，值为被评论微博的ID。如果回复某条评论，则此值为该评论的id。</param>
        /// <param name="statues">必选参数，评论内容</param>
        /// <param name="isRetweet">可选参数，是否转发 默认不转发 1为转发</param>
        /// <param name="isCommentToRoot">是否评论给原微博 默认不评论 1为评论</param>
        /// <returns></returns>
        public void Reply(Action<OAuthResponse> action, Action<Exception> fail, string id, Statues statues, string isRetweet = "0", string isCommentToRoot = "0")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.Reply).AddParameter(
                new Parameter[] {
                    new Parameter("id", id),
                    new Parameter("status", statues.Text),
                    new Parameter("is_retweet", isRetweet),
                    new Parameter("is_comment_to_root", isCommentToRoot)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 转发一条微博
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，值为被转发微博的ID</param>
        /// <param name="statues">可选参数，评论内容，默认为“转发微博。”</param>
        /// <param name="isComment">可选参数，是否评论 默认不评论 1为评论</param>
        /// <param name="isCommentToRoot">可选参数，是否评论给原微博 默认不评论 1为评论</param>
        /// <returns></returns>
        public void Retweet(Action<OAuthResponse> action, Action<Exception> fail, string id, string isComment = "0", string isCommentToRoot = "0", Statues statues = null)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(string.Format(Urls.Retweet, id)).AddParameter(
                new Parameter[] {
                    new Parameter("id", id),
                    new Parameter("status", statues == null ? "转发微博" : statues.Text),
                    new Parameter("is_comment", isComment),
                    new Parameter("is_comment_to_root", isCommentToRoot)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取单条微博信息
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，值为微博的ID</param>
        /// <returns></returns>
        public void Show(Action<OAuthResponse> action, Action<Exception> fail, string id)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(string.Format(Urls.Show, id)).AddParameter(
                new Parameter("id", id)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 查看指定微博的所有评论
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，指定的微博id</param>
        /// <param name="sinceId">可选参数，该参数需传微博id，返回此条索引之后发的微博列表，不包含此条</param>
        /// <param name="maxId">可选参数，该参数需传微博id，返回此条微博之前发的微博列表，包含此条</param>
        /// <param name="count">可选参数，数量，默认为30条，最大为200条</param>
        /// <param name="trimUser">可选参数，值为true时返回的user对象只包含id属性，该参数能在一定程度上减少返回的数据量</param>
        /// <returns></returns>
        public void Comments(Action<OAuthResponse> action, Action<Exception> fail, string id, int count = 30, bool trimUser = true, string sinceId = "", string maxId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(string.Format(Urls.Comments, id)).AddParameter(
                new Parameter("since_id", sinceId),
                new Parameter("max_id", maxId),
                new Parameter("count", count.ToString()),
                new Parameter("trim_user", trimUser ? "true" : "false")).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 删除指定的微博，也可以撤销已转发的微博
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，值为删除或撤销转发微博的ID</param>
        /// <returns></returns>
        public void Destroy(Action<OAuthResponse> action, Action<Exception> fail, string id)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(string.Format(Urls.Destroy, id)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取一条微博被转发的用户信息
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，值为被转发微博的ID</param>
        /// <param name="count">可选参数，返回的用户数量，默认为100条，最大100条</param>
        /// <returns></returns>
        public void GetRetweetedBy(Action<OAuthResponse> action, Action<Exception> fail, string id, int count = 30)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(string.Format(Urls.RetweetedBy, id)).AddParameter(
                new Parameter("count", count.ToString())).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 上传图片文件并返回图片地址,将获得的图片地址通过发微博(statuses/update)接口附在微博正文里一同发出，则得到一个包含图片的微博
        /// </summary>
        /// <param name="fileName">图片名字，必选参数，支持jpg、png、bmp、gif这四种图片格式，上传图片大小在20M以内,此参数不参与Oauth签名。Oauth相关的验证参数请直接放在Header里</param>
        /// <param name="fileBytes">图片</param>
        /// <returns></returns>
        private void UploadPic(Action<OAuthResponse> action, Action<Exception> fail, string fileName, byte[] image)
        {
            var boundary = Guid.NewGuid().ToString();
            var request = (HttpWebRequest)System.Net.WebRequest.Create(Urls.Upload);

            request.AllowReadStreamBuffering = true;
            request.Method = "POST";

            string oauthherad = OAuthUtility.GenerateAuthorizationHeader(realm, Urls.Upload, string.Empty, HttpMethodType.Post, this.Consumer, this.AccessToken, realm, new Parameter[] { });

            request.Headers["Authorization"] = oauthherad;

            var header = string.Format("--{0}", boundary);
            var footer = string.Format("--{0}--", boundary);

            var contents = new StringBuilder();
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);

            contents.AppendLine(header);
            contents.AppendLine("Content-Type: text/plain; charset=US-ASCII");
            contents.AppendLine("Content-Transfer-Encoding: 8bit");
            contents.AppendLine();
            contents.AppendLine(this.Consumer.ConsumerKey);

            contents.AppendLine(header);
            string fileHeader = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", "pic", fileName);
            string fileData = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(image, 0, image.Length);

            contents.AppendLine(fileHeader);
            contents.AppendLine("Content-Type: application/octet-stream; charset=UTF-8");
            contents.AppendLine("Content-Transfer-Encoding: binary");
            contents.AppendLine();
            contents.AppendLine(fileData);
            contents.AppendLine(footer);

            byte[] bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(contents.ToString());

            try
            {
                request.BeginGetRequestStream(p =>
                {
                    try
                    {
                        HttpWebRequest req = (HttpWebRequest)(((object[])p.AsyncState)[0]);
                        byte[] postBytes = (byte[])(((object[])p.AsyncState)[1]);
                        Stream postStream = req.EndGetRequestStream(p);
                        postStream.Write(postBytes, 0, postBytes.Length);
                        postStream.Close();

                        req.BeginGetResponse(o =>
                        {
                            try
                            {
                                HttpWebRequest getReq = (HttpWebRequest)o.AsyncState;
                                HttpWebResponse response = (HttpWebResponse)getReq.EndGetResponse(o);

                                OAuthResponse oauthResponse = new OAuthResponse(response);

                                action(oauthResponse);

                                response.Close();
                            }
                            catch (Exception ex)
                            {
                                HandleErrors(ex, fail);
                            }
                        }, req);
                    }
                    catch (Exception ex)
                    {
                        HandleErrors(ex, fail);
                    }
                }, new object[] { request, bytes });
            }
            catch (Exception ex)
            {
                HandleErrors(ex, fail);
            }
        }

        /// <summary>
        /// 发布图片微博
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="fileName">图片路径，必选参数，支持jpg、png、bmp、gif这四种图片格式，上传图片大小在20M以内,此参数不参与Oauth签名。Oauth相关的验证参数请直接放在Header里</param>
        /// <param name="text">文字内容</param>
        /// <param name="lat">选参数，即纬度。范围在+90.0 到 -90.0，如果超出这个范围则忽略该值，必须与long参数一起使用，否则忽略该值。只有当用户的geo_enable为true时才有效</param>
        /// <param name="longGeo">可选参数,即经度。范围在+180.0到-180.0，如果超出这个范围则忽略该值，必须与lat参数一起使用，否则忽略该值。只有当用户的geo_enable为true时才有效</param>
        /// <param name="vid">可选参数,即 POI 的 ID，某一个具体的地点，比如天安门</param>
        /// <returns></returns>
        public void Upload(Action<OAuthResponse> action, Action<Exception> fail, string fileName, byte[] image, string text = "", double lat = 0, double longGeo = 0, string vid = "")
        {
            UploadPic(up =>
                {
                    if (up.IsSuccess && !string.IsNullOrWhiteSpace(up.ResponseText))
                    {
                        JObject jobj = JObject.Parse(up.ResponseText);

                        Update(action, fail, new Statues { Text = text + jobj["upload_image_url"].Value<string>() }, lat, longGeo, vid);
                    }
                }, fail, fileName, image);
        }

        #endregion
        
        #region 用户

        /// <summary>
        /// 获取指定用户信息
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">可选参数，用户的个性网址或用户ID</param>
        /// <param name="name">可选参数，用户的昵称</param>
        /// <param name="user_id">可选参数，用户ID</param>
        /// <param name="screen_name">用户的个性网址</param>
        /// <returns></returns>
        public void UserShow(Action<OAuthResponse> action, Action<Exception> fail, string screen_name, string id = "", string name = "", string user_id = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.UserShow).AddParameter(
                    new Parameter[] { 
                        new Parameter("id", id),
                        new Parameter("screen_name", screen_name),
                        new Parameter("name", name),
                        new Parameter("user_id", user_id)
                    }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取指定用户的关注用户列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <param name="cursor">可选参数，分页参数，单页只能包含30个关注列表</param>
        /// <returns></returns>
        public void Friends(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "", int cursor = 1)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Friends).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName),
                new Parameter("cursor", cursor.ToString())
                ).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess)
            //{
            //    var fans = new { next_cursor = "1", users = new List<Users>(), previous_cursor = "-1" };
            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, fans).users;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 获取指定被关注用户列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="cursor">可选参数，分页参数，单页只能包含30个关注列表</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <returns></returns>
        public void Followers(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "", int cursor = 1)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Followers).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName),
                new Parameter("cursor", cursor.ToString())
                ).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess)
            //{
            //    var fans = new { next_cursor = "1", users = new List<Users>(), previous_cursor = "-1" };
            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, fans).users;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 返回用户可能感兴趣的用户，随机返回指定数目的用户
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="count">可选参数，指定随机返回的用户数目。默认为30个，最多返回30个</param>
        /// <param name="trimUser">可选参数，值为true时返回最基本的用户数据，使用此参数可以减少返回数据量，默认为false</param>
        /// <returns></returns>
        public void Suggestions(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, bool trimUser = false)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Suggestions).AddParameter(
                new Parameter("count", count.ToString()),
                new Parameter("trim_user", trimUser ? "true" : "false")).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess)
            //{
            //    var slst = new { users = new List<Users>() };
            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, slst).users;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 获取推荐的I达人的用户列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="cursor">可选参数，分页参数</param>
        /// <param name="trimUser">可选参数，值为true时返回最基本的用户数据，使用此参数可以减少返回数据量，默认为false</param>
        /// <returns></returns>
        public void SuggestionsIFollowers(Action<OAuthResponse> action, Action<Exception> fail, string cursor, bool trimUser = false)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.SuggestionsIFollowers).AddParameter(
                new Parameter("cursor", cursor),
                new Parameter("trim_user", trimUser ? "true" : "false")).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess)
            //{
            //    var silst = new { users = new List<Users>() };
            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, silst).users;
            //}
            //else
            //    return null;
        }

        #endregion
        
        #region 关注

        /// <summary>
        /// 关注指定用户
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <returns></returns>
        public void FriendshipsCreate(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.FriendshipCreate).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取两个用户的相互关注关系
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sourceId">可选参数，指定用户的userId</param>
        /// <param name="sourceScreenName">可选参数，指定用户的个性网址</param>
        /// <param name="targetId">可选参数，指定用户的userId</param>
        /// <param name="targetScreenName">可选参数，目标用户的个性网址</param>
        /// <returns></returns>
        public void FriendshipsShow(Action<OAuthResponse> action, Action<Exception> fail, string targetId = "", string targetScreenName = "", string sourceId = "", string sourceScreenName = "")
        {
            if (string.IsNullOrWhiteSpace(targetId) && string.IsNullOrWhiteSpace(targetScreenName))
            {
                throw new ArgumentNullException("target_id 和 target_screen_name 不能同时为空。", "targetId/targetScreenName");
            }

            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.FriendshipShow).AddParameter(
                new Parameter[] {
                    new Parameter("source_id", sourceId),
                    new Parameter("source_screen_name", sourceScreenName),
                    new Parameter("target_id", targetId),
                    new Parameter("target_screen_name", targetScreenName)
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 取消关注指定用户
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <returns></returns>
        public void FriendshipsDestroy(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.FriendshipDestroy).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName)).CommitRequest();

            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 热榜

        /// <summary>
        /// 获取当前的热门转发榜
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="type">必选参数，排行榜类型,当前有4种:oneHour,sixHours,oneDay,oneWeek</param>
        /// <param name="size">可选参数，返回数量,不传则为默认值(当前为50),最多50</param>
        /// <returns></returns>
        public void TopRetweets(Action<OAuthResponse> action, Action<Exception> fail, string type = "oneHour", int size = 50)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.TopRetweets).AddParameter(
                new Parameter("type", type),
                new Parameter("size", size.ToString())).CommitRequest();

            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 话题

        /// <summary>
        /// 推荐话题API，其效果与“我的首页”右侧的推荐话题一致
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void TrendsRecommended(Action<OAuthResponse> action, Action<Exception> fail)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.TrendsRecommended).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess)
            //{
            //    var Trends = new { trends = new List<Trend>() };

            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, Trends).trends;
            //}
            //else
            //    return null;
        }

        #endregion
        
        #region 私信

        /// <summary>
        /// 获取当前用户私信列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，上一页最后一条私信的id</param>
        /// <param name="count">可选参数，获取私信的数量</param>
        /// <returns></returns>
        public void DirectMessages(Action<OAuthResponse> action, Action<Exception> fail, int count = 20, string sinceId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.DirectMessages).AddParameter(
                new Parameter("count", count.ToString()), new Parameter("since_id", sinceId)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 获取当前用户发送的私信列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="sinceId">可选参数，上一页最后一条私信的id</param>
        /// <param name="count">可选参数，获取私信的数量</param>
        /// <returns></returns>
        public void DirectMessageSent(Action<OAuthResponse> action, Action<Exception> fail, int count = 20, string sinceId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.DirectMessagesSent).AddParameter(
                new Parameter("count", count.ToString()), new Parameter("since_id", sinceId)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 发送一条私信
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userName">必选参数，收信用户的昵称，即name</param>
        /// <param name="text">必选参数，私信内容</param>
        /// <returns></returns>
        public void DirectMessageNew(Action<OAuthResponse> action, Action<Exception> fail, string userName, string text)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.DirectMessagesNew).AddParameter(
                new Parameter("user", userName),
                new Parameter("text", text)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 删除一条私信
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，删除的私信id</param>
        /// <returns></returns>
        public void DirectMessageDestory(Action<OAuthResponse> action, Action<Exception> fail, string id)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(string.Format(Urls.DirectMessageDestroy, id)).CommitRequest();
            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 帐号

        /// <summary>
        /// 网易通行证开通微博，当用户有通行证账号且未开通微博时，可以通过此API开通
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="idNum">可选参数，身份证号，如身份证号不合法，则返回400</param>
        /// <param name="mobile">可选参数，手机号，如手机号不合法，则返回400</param>
        /// <param name="nikeName">可选参数，昵称，如果昵称不合法，则返回400</param>
        /// <param name="realName">可选参数，真实姓名，如真实姓名不合法，则返回400</param>
        /// <returns>是否开通成功状态</returns>
        public void Activate(Action<OAuthResponse> action, Action<Exception> fail, string nikeName, string realName, string mobile, string idNum)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.Activate).AddParameter(
                new Parameter("nick_name", nikeName),
                new Parameter("real_name", realName),
                new Parameter("mobile", mobile),
                new Parameter("id_num", idNum)
                ).CommitRequest();

            request.GetResponse(action, fail);

            //if (result.IsSuccess && !string.IsNullOrWhiteSpace(result.ResponseText))
            //{
            //    var r = new { id = "id", error = "", parameter = "", request = "" };

            //    var rt = JsonConvert.DeserializeAnonymousType(result.ResponseText, r);

            //    if (result.StatusCode == HttpStatusCode.OK)
            //        return rt.id;
            //    else
            //        return rt.error;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 修改用户个人资料
        /// 本API只对高级第三方合作者开放，申请此API权限请发邮件到OpenAPI@yeah.net，未授权访问则返回403
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="nikeName">可选参数，昵称，如果昵称不合法，则返回400</param>
        /// <param name="realName">可选参数，真实姓名，如真实姓名不合法，则返回400</param>
        /// <param name="description">可选参数，用户描述，如超过163个字符，则返回400</param>
        /// <param name="province">可选参数，用户省份，如省份不合法，则返回400</param>
        /// <param name="city">可选参数，用户城市，如城市不合法，则返回400</param>
        /// <returns></returns>
        public void UpdateProfile(Action<OAuthResponse> action, Action<Exception> fail, string nikeName = "", string realName = "", string description = "", string province = "", string city = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.UpdateProfile).AddParameter(
                new Parameter("nick_name", nikeName),
                new Parameter("real_name", realName),
                new Parameter("description", description),
                new Parameter("province", province),
                new Parameter("city", city)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 修改用户个人头像
        /// 本API只对高级第三方合作者开放，申请此API权限请发邮件到OpenAPI@yeah.net，未授权访问则返回403
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="image">必选参数，图片路径。支持jpg、png、gif这三种图片格式，上传图片大小在4M以内</param>
        /// <returns></returns>
        public void UpdateProfileImage(Action<OAuthResponse> action, Action<Exception> fail, string fileName, byte[] imageData)
        {
            UploadPic(up =>
                {
                    if (up.IsSuccess && !string.IsNullOrWhiteSpace(up.ResponseText))
                    {
                        var uploadImage = new { upload_image_url = "image_address" };
                        var image = JsonConvert.DeserializeAnonymousType(up.ResponseText, uploadImage);

                        var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.UpdateProfielImage).AddParameter(new Parameter("image", image.upload_image_url)).CommitRequest();
                        request.GetResponse(action, fail);
                    }
                }, fail, fileName, imageData);            
        }

        /// <summary>
        /// 返回当前登录用户未读的新消息数量
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void Latest(Action<OAuthResponse> action, Action<Exception> fail)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Letest).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 返回当前小时内剩余访问次数
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <returns></returns>
        public void RateLimitStatus(Action<OAuthResponse> action, Action<Exception> fail)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.RateLimitStatus).CommitRequest();
            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 收藏

        /// <summary>
        /// 获取指定用户的收藏
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，可以为该用户的个性网址(screen_name)</param>
        /// <param name="count">返回微博数量，默认30，最大200</param>
        /// <param name="sinceId">分页参数，传微博ID,返回此条微博以前发的微博列表,不包含此条</param>
        /// <returns></returns>
        public void Favorites(Action<OAuthResponse> action, Action<Exception> fail, string id, int count = 30, string sinceId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(string.Format(Urls.Favorites, id)).AddParameter(
                new Parameter("count", count.ToString()),
                new Parameter("since_id", sinceId)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 添加收藏
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，要收藏的微博ID</param>
        /// <returns></returns>
        public void FavoritesCreate(Action<OAuthResponse> action, Action<Exception> fail, string id)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(string.Format(Urls.FavoritesCreate, id)).CommitRequest();
            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 删除当前用户的收藏
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="id">必选参数，要删除的微博ID</param>
        /// <returns></returns>
        public void FavoritesDestroy(Action<OAuthResponse> action, Action<Exception> fail, string id)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(string.Format(Urls.FavoritesDestroy, id)).CommitRequest();
            request.GetResponse(action, fail);
        }

        #endregion
        
        #region 黑名单

        /// <summary>
        /// 阻止指定用户
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <exception cref="System.ArgumentException">user_id 和 screen_name 不能同时为空。</exception>
        /// <returns></returns>
        public void BlocksCreate(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.BlocksCreate).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 取消已阻止的用户，即将该用户移除黑名单
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <returns></returns>
        public void BlocksDestroy(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.BlocksDestroy).AddParameter(
                new Parameter("user_id", userId),
                new Parameter("screen_name", screenName)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 判断是否已经阻止用户,如已阻止此用户则返回用户信息，如未阻止则返回状态404，同时提示“此用户未被加入黑名单”
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="userId">可选参数. 用户ID，主要是用来区分用户ID跟微博昵称相同产生歧义的情况</param>
        /// <param name="screenName">可选参数，该用户的个性网址，也可以传user_id</param>
        /// <returns></returns>
        public void BlocksExits(Action<OAuthResponse> action, Action<Exception> fail, string userId = "", string screenName = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Post).SetUrl(Urls.BlocksExists).AddParameter(
               new Parameter("user_id", userId),
               new Parameter("screen_name", screenName)).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 返回当前登录用户屏蔽的用户列表
        /// </summary>
        /// <returns></returns>
        public void Blocking(Action<OAuthResponse> action, Action<Exception> fail)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.BlocksBlocking).CommitRequest();
            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 已阻止的Id列表
        /// </summary>
        /// <exception cref="System.NotImplementedException">该方法未实现</exception>
        /// <returns></returns>
        public void BlockingIds()
        {
            // todo: 已阻止Id 列表
            throw new NotImplementedException();
        }

        #endregion
        
        #region 地址位置相关

        /// <summary>
        /// 返回指定位置附近或者符合搜索关键字的地点列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="lat">可选参数，即纬度。范围在+90.0 到 -90.0，如果超出这个范围则忽略该值，必须与long参数一起使用，否则忽略该值</param>
        /// <param name="longGeo">可选参数,即经度。范围在+180.0到-180.0，如果超出这个范围则忽略该值，必须与lat参数一起使用，否则忽略该值</param>
        /// <param name="count">可选参数，返回数据的个数，默认为10，最大为50</param>
        /// <param name="q">选参数，搜索关键字，必须与经纬度（lat,long）参数同时使用才有效，,根据定位的数据在用户所在的城市搜索相应的POI，如没有经纬度参数或无结果返回404</param>
        /// <returns></returns>
        public void GetVenues(Action<OAuthResponse> action, Action<Exception> fail, int count = 10, string q = "", double lat = 0, double longGeo = 0)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Venues).AddParameter(
                new Parameter[] {
                    new Parameter("lat", lat.ToString()),
                    new Parameter("long", longGeo.ToString()),
                    new Parameter("count", count.ToString()),
                    new Parameter("q", q)
                }).CommitRequest();

            request.GetResponse(action, fail);
            //if (result.IsSuccess)
            //{
            //    var Venues = new { venues = new List<Venue>() };

            //    return JsonConvert.DeserializeAnonymousType(result.ResponseText, Venues).venues;
            //}
            //else
            //    return null;
        }

        /// <summary>
        /// 通过经纬度或POI返回与地理位置相关的微博列表，如传经纬度则返回附近的微博列表，传POI的ID则返回此POI下的微博列表
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="lat">可选参数，即纬度。范围在+90.0 到 -90.0，如果超出这个范围则忽略该值，必须与long参数一起使用，否则忽略该值</param>
        /// <param name="longGeo">可选参数,即经度。范围在+180.0到-180.0，如果超出这个范围则忽略该值，必须与lat参数一起使用，否则忽略该值</param>
        /// <param name="vid">可选参数,即POI的id，单独使用时值返回包含此vid的微博。如果经纬度也同时传入，则将两种微博（包含vid或经纬度的）一起返回，按照发微博的时间倒序排列。如果根据vid找不到相应的poi且无定位参数时则返回404</param>
        /// <param name="sinceId">可选参数，该参数需传cursor_id,返回此条索引之前发的微博列表,不包含此条</param>
        /// <param name="maxId">可选参数，该参数需传cursor_id,返回此条索引之后发的微博列表，包含此条</param>
        /// <param name="count">可选参数，返回微博的个数，默认为30，最大为200</param>
        /// <returns></returns>
        public void LocationTimeLine(Action<OAuthResponse> action, Action<Exception> fail, int count = 30, double lat = 0, double longGeo = 0, string vid = "", string sinceId = "", string maxId = "")
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.LocationTimeLine).AddParameter(
                new Parameter[]{
                    new Parameter("lat", lat.ToString()),
                    new Parameter("long", longGeo.ToString()),
                    new Parameter("vid", vid),
                    new Parameter("count", count.ToString()),
                    new Parameter("since_id", sinceId),
                    new Parameter("max_id", maxId)
                }).CommitRequest();
            request.GetResponse(action, fail);
        }

        #endregion

        #region 搜索

        /// <summary>
        /// 搜索
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="q">必选参数，关键字,最大长度25,如果以#起始的关键字会作为tag搜索精确匹配</param>
        /// <param name="page">可选参数，当前页数，默认为第一页</param>
        /// <param name="perPage">可选参数，返回数量,最大20</param>
        /// <returns></returns>
        public void Search(Action<OAuthResponse> action, Action<Exception> fail, string q, int page = 1, int perPage = 20)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.Search).AddParameter(
                new Parameter[] {
                    new Parameter("q", q),
                    new Parameter("page", page.ToString()),
                    new Parameter("per_page", perPage.ToString())
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 搜索微博
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="q">必选参数，关键字,最大长度25,如果以#起始的关键字会作为tag搜索精确匹配</param>
        /// <param name="page">可选参数，当前页数，默认为第一页</param>
        /// <param name="perPage">可选参数，返回数量,最大20</param>
        /// <param name="trimUse">可选参数，值为true时返回的user对象只包含id属性，该属性能在一定程度上减少返回的数据量</param>
        /// <returns></returns>
        public void SearchStatus(Action<OAuthResponse> action, Action<Exception> fail, string q, int page = 1, int perPage = 20, bool trimUse = true)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.StatuesSearch).AddParameter(
                new Parameter[] {
                    new Parameter("q", q),
                    new Parameter("page", page.ToString()),
                    new Parameter("per_page", perPage.ToString()),
                    new Parameter("trim_user", trimUse ? "true" : "false")
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        /// <summary>
        /// 搜索用户
        /// </summary>
        /// <param name="action">处理请求返回的数据</param>
        /// <param name="fail">错误处理方法</param>
        /// <param name="q">必选参数，关键字,最大长度25</param>
        /// <param name="page">可选参数，当前页数，默认为第一页</param>
        /// <param name="perPage">可选参数，返回数量,最大20</param>
        /// <returns></returns>
        public void SearchUser(Action<OAuthResponse> action, Action<Exception> fail, string q, int page = 1, int perPage = 20)
        {
            var request = requestBase.SetHttpMethod(HttpMethodType.Get).SetUrl(Urls.UserSearch).AddParameter(
                new Parameter[] {
                    new Parameter("q", q),
                    new Parameter("page", page.ToString()),
                    new Parameter("per_page", perPage.ToString())
                }).CommitRequest();

            request.GetResponse(action, fail);
        }

        #endregion
    }
}
